﻿//-----------------------------------------------------------------------
// <copyright file="DirectoryAssemblyFinder.cs" company="SLWY Enterprises">
// * Copyright (C) 2017 四川商旅无忧科技有限公司 版权所有。
// * version : 1.0
// * author  : qinchaoyue
// * FileName: DirectoryAssemblyFinder.cs
// * history : created by qinchaoyue 2017-10-24 03:35:39
// *            2017年10月28日 00:51:46 修复因为 nuget 不把 dll 复制到 bin 文件夹而不能获取到程序集问题
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.Extensions.DependencyModel;

namespace Slwy.FrameCore.Reflection
{
    /// <summary>
    /// 程序集查找类
    /// </summary>
    public class DirectoryAssemblyFinder : IAllAssemblyFinder
    {
        /// <summary>
        /// 程序集缓存
        /// </summary>
        private static readonly IDictionary<string, Assembly[]> AssembliesesDict = new Dictionary<string, Assembly[]>();

        /// <summary>
        /// 程序路径
        /// </summary>
        private readonly string path;

        /// <summary>
        /// Initializes a new instance of the <see cref="DirectoryAssemblyFinder"/> class.
        /// </summary>
        public DirectoryAssemblyFinder()
            : this(GetBinPath())
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DirectoryAssemblyFinder"/> class.
        /// 构造
        /// </summary>
        /// <param name="path"> The path.  </param>
        public DirectoryAssemblyFinder(string path)
        {
            this.path = path;
        }

        /// <summary>
        /// 获取程序路径
        /// </summary>
        /// <returns>程序路径</returns>
        private static string GetBinPath()
        {
            var path = AppDomain.CurrentDomain.BaseDirectory;
            return path;

            // return path == Environment.CurrentDirectory + "\\" ? path : Path.Combine(path, "bin");
        }

        /// <summary>
        /// 获取条件中的程序集
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns>程序集</returns>
        public Assembly[] Find(Func<Assembly, bool> predicate)
        {
            return this.FindAll().Where(predicate).ToArray();
        }

        /// <summary>
        /// 获取所有程序集
        /// </summary>
        /// <returns>所有程序集</returns>
        public Assembly[] FindAll()
        {
            if (AssembliesesDict.ContainsKey(this.path))
            {
                return AssembliesesDict[this.path];
            }


            var assemblies = new List<Assembly>();
            DependencyContext.Default.CompileLibraries.Where(m => m.Name.IndexOf("Slwy", StringComparison.Ordinal) != -1).ToList().ForEach(m =>
            {
                try
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(m.Name));
                    assemblies.Add(assembly);
                }
                catch
                {
                }
            });

            string[] files = Directory.GetFiles(this.path, "Slwy*.dll", SearchOption.TopDirectoryOnly)
                      .Concat(Directory.GetFiles(this.path, "Slwy*.exe", SearchOption.TopDirectoryOnly))
                      .ToArray();
            
            assemblies.AddRange(files.Select(Assembly.LoadFrom).Distinct().ToArray());
            var assembliesArray = assemblies.Distinct().ToArray();
 
             AssembliesesDict.Add(this.path, assembliesArray);
            return assembliesArray;
        }
    }
}
